package cn.fatgod.learn.thymeleaf.standard.interfaces;

import cn.fatgod.learn.thymeleaf.standard.PropUtils;
import org.thymeleaf.context.Context;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;

/**
 * 数据绑定器接口
 */
public interface IDataBinder {
    /**
     * 无用的context
     */
    Context BUM = new Context();

    /**
     * NULL
     */
    Object NULL = null;

    /**
     * 数据绑定
     */
    default Context bind() {
        if (!this.isEnable()) {
            return BUM;
        }
        Class<? extends IDataBinder> clazz = this.getClass();
        Bind typeBind = clazz.getAnnotation(Bind.class);
        if (typeBind != null && !typeBind.value()) {
            return BUM;
        }
        Field[] fields = clazz.getDeclaredFields();
        try {
            Context context = new Context();
            for (Field field : fields) {
                Bind fieldBind = field.getAnnotation(Bind.class);
                if (fieldBind != null && !fieldBind.value()) {
                    continue;
                }
                Object obj = this.convert(PropUtils.getValue(this, field));
                if (obj == NULL) {
                    continue;
                }
                context.setVariable(field.getName(), obj);
            }
            return context;
        } catch (Exception e) {
            throw new RuntimeException("context上下文数据绑定错误", e);
        }
    }

    default Object convert(Object obj) {
        if (obj == NULL) {
            return NULL;
        }
        if (obj instanceof BinderType) {
            return ((BinderType) obj).getCode();
        }
        if (obj instanceof IDataBinder) {
            Context cxt = ((IDataBinder) obj).bind();
            return isUseful(cxt) ? cxt : NULL;
        }
        if (obj instanceof Iterable) {
            List<Object> objs = new ArrayList<>();
            for (Object item : (Iterable<?>) obj) {
                if (item == NULL) {
                    continue;
                }
                Object convertObj = convert(item);
                if (convertObj != NULL) {
                    objs.add(convertObj);
                }
            }
            return objs;
        }
        return obj;
    }

    /**
     * 是否启用
     *
     * @return 启用标志
     */
    default boolean isEnable() {
        return true;
    }

    /**
     * 是否启用
     *
     * @return 启用标志
     */
    static boolean isUseful(Context context) {
        if (context == null) {
            return false;
        }
        return context != BUM;
    }
}
